using System.Text.Json;
using Infrastructure;
using Application;
using Application.KafkaService;
using Common;
using EntityGraphQL.AspNet;
using Grpc.Services;
using KafkaFlow;
using KafkaFlow.Serializer;
using Microsoft.AspNetCore.Http.Timeouts;
using Microsoft.AspNetCore.RateLimiting;
using WebApi.MappingProfiles;
using Microsoft.EntityFrameworkCore;
using Refit;
using Scalar.AspNetCore;
using SDK;
using ServiceDefaults;
using ShardingCore;
using WebApi.Middleware;
using WebApi.Setups;

namespace WebApi
{
    /// <summary>
    /// 
    /// </summary>
    public class Program
    {
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.
            builder.AddServiceDefaults();
            builder.Services.AddProblemDetails();

            builder.Services.AddGrpc();
            builder.Services.AddControllers().AddJsonOptions(configure =>
            {
                configure.JsonSerializerOptions.Converters.Add(new JsonConverterDatetime());
                configure.JsonSerializerOptions.Converters.Add(new JsonConverterLong());
            });

            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();

            builder.Services.AddSwaggerService();

            builder.Services.AddDbContext<UserDbContext>(option =>
            {
                var connStr = builder.Configuration.GetConnectionString("uc_mysql");
                option.UseMySql(connStr, ServerVersion.AutoDetect(connStr));
            });
            
            //额外添加分片配置
            // builder.Services.AddShardingDbContext<UserDbContext>()
            //     .UseRouteConfig(op =>
            //     {
            //         op.AddShardingTableRoute<OrderVirtualTableRoute>();
            //     }).UseConfig(op =>
            //     {
            //         op.UseShardingQuery((connStr, builder) =>
            //         {
            //             //connStr is delegate input param
            //             builder.UseMySql(connStr,ServerVersion.AutoDetect(connStr));
            //         });
            //         op.UseShardingTransaction((connection, builder) =>
            //         {
            //             //connection is delegate input param
            //             builder.UseMySql(connection.ConnectionString,ServerVersion.AutoDetect(connection.ConnectionString));
            //         });
            //         //use your data base connection string
            //         op.AddDefaultDataSource("uc_mysql",builder.Configuration.GetConnectionString("uc_mysql"));
            //     }).AddShardingCore();
            
            
            builder.Services.AddGraphQLSchema<UserDbContext>();

            builder.Services.AddApplication().AddInfrastructure();

            builder.Services.AddAutoMapper(cfg => { cfg.AddProfile<ApiMappingProfile>(); });

            builder.Services.AddAuthService(builder.Configuration);
            
            builder.Services.AddOpenApi();
            
            builder.Services.AddHostedService<KafkaConsumerService>();
            
            // 注册Refit客户端
            builder.Services.AddRefitClient<IUserService>(new RefitSettings
            {
                ContentSerializer = new NewtonsoftJsonContentSerializer()
                
            }).ConfigureHttpClient(c => c.BaseAddress = new Uri("http://localhost:5090"));

            builder.Services.AddRateLimiter(p => p.AddFixedWindowLimiter("FixedWindow", options =>
            {
                options.PermitLimit = 3;
                options.Window = TimeSpan.FromSeconds(10);
            }));

            builder.Services.AddRequestTimeouts(options =>
            {
                options.DefaultPolicy = new RequestTimeoutPolicy() { Timeout = TimeSpan.FromSeconds(5) };
                //options.AddPolicy("TimeOutPolicy", TimeSpan.FromSeconds(5));
            });

            var app = builder.Build();
            app.UseRateLimiter();
            app.UseRequestTimeouts();
            app.UseMiddleware<TraceIdMiddleware>();
            app.MapGraphQL<UserDbContext>();
            app.MapGrpcService<GreeterService>();

            app.UseSwaggerService(app.Environment);
            if (app.Environment.IsDevelopment())
            {
                app.MapOpenApi();
                app.MapScalarApiReference();
            }

            using (var scope = app.Services.CreateScope())
            {
                var dbContext = scope.ServiceProvider.GetRequiredService<UserDbContext>();
                if (dbContext.Database.GetPendingMigrations().Any())
                    dbContext.Database.Migrate();
                
                //app.Services.UseAutoTryCompensateTable();
            }

            app.UseAuthentication();

            app.UseAuthorization();

            app.MapControllers();

            app.Run();
        }
    }
}